#pragma once

#include "Thread.h"
#include "MultiThreadedQueue.h"
#include "IThreadPoolWorkerJob.h"
#include <vector>
#include <memory>

namespace GPUCC
{
	namespace CPU
	{
		class ThreadPool
		{
		public:
			ThreadPool();
			~ThreadPool();

			bool Start(unsigned int NumberOfWorkers);
			bool StartAndJoin(unsigned int NumberOfAdditionalWorkers);
			void Stop();
			void StopAndWait();
			
			bool IsRunning();
			bool DidJoin();
			unsigned int GetNumberOfWrokers();

			void AddJobExecution(std::shared_ptr<IThreadPoolWorkerJob> JobToExecute);

		private:
			class ThreadPoolWorkerThreadLogic : public IThreadable
			{
			public:
				ThreadPoolWorkerThreadLogic(ThreadPool& Instance);
				~ThreadPoolWorkerThreadLogic();

				virtual void Run();
				virtual void Stop();
			
			private:
				ThreadPool& m_Instance;
			};

			bool StartWorkerThreads(unsigned int NumberOfWorkers);
			void WaitForWorkers();

			bool m_IsRunning;
			bool m_DidJoin;
			unsigned int m_NumberOfWorkers;
			std::vector<std::shared_ptr<Thread>> m_Threads;
			ThreadPoolWorkerThreadLogic m_ThreadLogic;
			MultiThreadedQueue<std::shared_ptr<IThreadPoolWorkerJob>> m_PendingJobs;
		};
	}
}